<html lang="en">
<head>
<title>Test</title>
<script type="text/javascript">

    var sampleTags = ["apple", "raspberry", "blackberry", "pine", "pear", "currant", "pineapple", "mango", "cherry"];

    var curSuggestions = new Array();

    var array = null;
    var running = false;

    function go(suggestions) {
        array = suggestions;
        if (!running) {
            running = true;
            var result;
            while (array != null) {
                a = array;
                array = null;
                result = mergeSuggestions(a);
            }
            curSuggestions = updateSuggestions(result)
            running = false;
        }
    }

    function mergeSuggestions(newSuggs) {
        var newSuggestions = new Array();
        var idx = 0, i;

        // removal of duplicated elements
        for (i = 0; i < newSuggs.length; i++) {
            if (newSuggs[i].findIn(newSuggestions) == null) {
                newSuggestions[idx++] = newSuggs[i];
            }
        }

        // merging incoming suggestions with current ones
        var mergedSuggestions = new Array();
        idx = 0;
        var sugg;
        for (i = 0; i < newSuggestions.length; i++) {
            var curSugg = newSuggestions[i].findIn(curSuggestions);
            if (curSugg == null || curSugg.removed) {
                sugg = new Suggestion(newSuggestions[i].tag, null, i);
                mergedSuggestions[idx++] = sugg;
            } else {
                sugg = new Suggestion(curSugg.tag, curSugg.curPos, i);
                mergedSuggestions[idx++] = sugg;
            }
        }

        for (i = 0; i < curSuggestions.length; i++) {
            if (curSuggestions[i].removed) continue;
            var newSugg = curSuggestions[i].findIn(newSuggestions);
            if (newSugg == null) {
                sugg = new Suggestion(curSuggestions[i].tag, curSuggestions[i].curPos, null);
                mergedSuggestions[idx++] = sugg;
            }
        }

        return mergedSuggestions;
    }


    function updateSuggestions(curSuggestions) {
        document.getElementById("log").value += "-----\n";

        var i, sugg;
        for (i = 0; i < curSuggestions.length; i++) {
            sugg = curSuggestions[i];
            document.getElementById("log").value += "new(" + sugg.toString() + ")\n";
            if (sugg.newPos != null) {
                if (sugg.curPos == null) {
                    addNewSprite(sugg);
                } else {
                    moveInToList(sugg);
                }
            } else {
                break;
            }
        }

        var dropBound = i;

        for (; i < curSuggestions.length; i++) {
            sugg = curSuggestions[i];
            moveOutFromList(sugg);
        }

        return curSuggestions;
    }

    function Suggestion(tag, curPos, newPos) {
        this.tag = tag;
        this.curPos = curPos;
        this.newPos = newPos;
        this.removed = false;

        this.findIn = function(suggestions) {
            for (var i = 0; i < suggestions.length; i++) {
                if (suggestions[i].tag == this.tag && !suggestions[i].removed)
                    return suggestions[i];
            }

            return null;
        };

        this.toString = function() {
            return "Suggestion(tag=" + this.tag + ", curPos=" + this.curPos + ", newPos=" + this.newPos + ", removed=" + this.removed + ");"
        }
    }


    function printSuggestions(suggestions) {
        for (var i = 0; i < suggestions.length; i++) {
            putLine(suggestions[i].toString());
        }
    }

    function sugTest() {
        var suggs = new Array();

        for (var i = 0; i < 5; i++) {
            suggs[i] = new Suggestion(sampleTags[Math.round(Math.random() * sampleTags.length) % sampleTags.length], null, i);
        }

        go(suggs);

    }

    function addNewSprite(sugg) {
        var panel = document.getElementById("spritePanel");

        if (document.getElementById("sprite-" + sugg.tag) == null) {
            var sprite = document.createElement("div");
            sprite.setAttribute("id", "sprite-" + sugg.tag);
            sprite.setAttribute("class", "sprite");
            sprite.setAttribute("style", "-webkit-transform: translate3d(500px, 400px, 50px) rotateY(60deg) ; -webkit-transition: -webkit-transform 500ms ease-in-out; -webkit-transform-style: preserve-3d;");
            sprite.appendChild(document.createTextNode(sugg.tag));
            panel.appendChild(sprite);
            setTimeout(function() {
                moveInToList(sugg);
            }, 100);
        }

    }

    function moveInToList(sugg) {
        if (sugg.newPos != null) {
            var sprite = document.getElementById("sprite-" + sugg.tag);
            if (sprite != null) {
                sprite.addEventListener("webkitTransitionEnd", function() {
                    sugg.curPos = sugg.newPos;
                }, false);

                sprite.style.webkitTransition = "-webkit-transform 500ms ease-in-out";
                sprite.style.webkitTransform = "rotateY(0) translate3d(300px, " + (sugg.newPos * 50) + "px, -50px)";
            }
        }
    }

    function dropSprite(sprite) {
        var panel = document.getElementById("spritePanel");
        try {
            panel.removeChild(sprite);
        } catch (e) {

        }
    }

    function moveOutFromList(sugg) {
        if (sugg.newPos == null) {
            var sprite = document.getElementById("sprite-" + sugg.tag);
            if (sprite != null) {
                sprite.addEventListener("webkitTransitionEnd", function() {
                    sugg.removed = true;
                    dropSprite(sprite);
                }, false);

                sprite.style.webkitTransform = "translate3d(100px, 400px, 50px) rotateY(-60deg)";
                sprite.style.webkitTransition = "-webkit-transform 500ms ease-in-out"
            }
        }
    }

</script>

<style type="text/css">
    div.sprite {
        width: 200px;
        height: 20px;
        border: solid 3px black;
        position: absolute;
        left: 0;
        top: 0;
        text-align: center;
        background-color: #abc;

    }
</style>
</head>
<body id="body">
<div style="margin-left:50%;">
    <div id="spritePanel" style="-webkit-perspective: 800; perspective: 800; width: 800px; margin-left: -400px; margin-top: 100px; border: 1px solid black; height: 50%; -webkit-transform-style: preserve-3d;" onclick="sugTest();">
    </div>
    <div>
        <textarea id="log" style="margin-left: -500px; width: 1000px;"></textarea>
    </div>

</div>
</body>
</html>
